#ifndef __SWARM_TASKTAG__
#define __SWARM_TASKTAG__

#include "../common/TaskTag.hpp"

template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
class BoolTaskTag {
public:
  mutable std::array<bool_tag_elem_t, TASKTAGDIM> m_arr;

  template <typename... TagVals> constexpr 
   BoolTaskTag(TagVals... tagVals) : m_arr{{std::forward<TagVals>(tagVals)...}}{
    static_assert(TASKTAGDIM == sizeof...(TagVals), "ERROR");
  }

  BoolTaskTag(const std::array<bool_tag_elem_t, TASKTAGDIM> &arr) : m_arr(arr) {}

  BoolTaskTag() : m_arr(toArray(makeIdenticalTuple<bool, TASKTAGDIM>::make(false))) {}

  // Find a workaround to make this constexpr
  // See for instance: https://gist.github.com/1457531
  bool_tag_elem_t &operator[](int i) const {
    return m_arr[i];
  }
};


template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
class SwarmTaskTag : public TaskTag <TASK_ID, TASKTAGDIM, TASKDIM> {
public:
  BoolTaskTag<TASK_ID, TASKTAGDIM, TASKDIM> m_btt;

  SwarmTaskTag() = delete;

  SwarmTaskTag(const SwarmTaskTag *swt) : 
    TaskTag<TASK_ID, TASKTAGDIM, TASKDIM>(((const TaskTag<TASK_ID, TASKTAGDIM, TASKDIM> *)swt)->m_arr), 
    m_btt(swt->m_btt.m_arr)
  {
#ifdef DEBUG
    SEQUENTIAL_DUMP1("DEEP COPY SwarmTaskTag \n");
#endif
  }
  
  template <typename... TagVals> constexpr 
  SwarmTaskTag(const std::array<bool, TASKTAGDIM> &arr, TagVals... tagVals) : 
    TaskTag <TASK_ID, TASKTAGDIM, TASKDIM> (std::forward<TagVals>(tagVals)...), 
    m_btt(arr) 
  {
    static_assert(TASKTAGDIM == sizeof...(TagVals), "ERROR");
  }

  template <typename... TagVals> constexpr 
  SwarmTaskTag(TagVals... tagVals) : 
    TaskTag <TASK_ID, TASKTAGDIM, TASKDIM> (std::forward<TagVals>(tagVals)...), 
    m_btt() 
  {
    static_assert(TASKTAGDIM == sizeof...(TagVals), "ERROR");
  }
  
};

template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
ostream& operator<<(ostream& stream, BoolTaskTag<TASK_ID, TASKTAGDIM, TASKDIM> const &tt) {
  stream << "type=" << TASK_ID << ": ";
  for (int64_t i=0; i<TASKTAGDIM; ++i)
    stream << tt[i] << " ";  
  return stream;
}

template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
ostream& operator<<(ostream& stream, SwarmTaskTag<TASK_ID, TASKTAGDIM, TASKDIM> const &tt) {
  const TaskTag<TASK_ID, TASKTAGDIM, TASKDIM> &t = 
    static_cast<const TaskTag<TASK_ID, TASKTAGDIM, TASKDIM> &>(tt);
  stream << t << " " << tt.m_btt << "\n";
  return stream;
}

#endif // __SWARM_TASKTAG__

